package TCPClient;
import java.io.*;
import java.net.*;
import java.util.HashMap;
import java.util.Map;

import messangerClient.ClientUI;
import messangerTypes.*;

public class TCPClient
{
	private Socket socket;
	private TCPSendWorker sendWorker;
	private TCPReadWorker readWorker;
	private ObjectOutputStream out;
	private User user;
	private Map <Integer, ClientUI> guis;
	
	//for debugging without GUI
	public TCPClient ()
	{
		try
		{
			this.socket = new Socket("localhost", 6789);
			User user = new User("Doug", "Sweeney", 0, "Password");
			this.guis = new HashMap<Integer, ClientUI> ();
			sendWorker = new TCPSendWorker(user, socket.getOutputStream());
			readWorker = new TCPReadWorker(this, user, socket.getInputStream());
			
			readWorker.join();
			sendWorker.join();
			
			sendWorker.start();
			readWorker.start();
			
		} catch (Exception e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void registerClientGUI (ClientUI ui, User user)
	{
		this.guis.put(user.getId(), ui);
	}
	
	public void removeClientGUI (User user)
	{
		this.guis.remove(user.getId());
	}
	
	public TCPClient (User user) throws Exception
	//throws because if creation fails client program is dead
	{
			this.socket = new Socket("localhost", 6789);
			this.user = user;
			this.guis = new HashMap<Integer, ClientUI> ();
			//create the object stream for
			out = new ObjectOutputStream(this.socket.getOutputStream());
			
			//start the worker thread
			readWorker = new TCPReadWorker(this, user, socket.getInputStream());
			readWorker.join();
			readWorker.start();
	}
	
	public void close ()
	{
		sendWorker.quit = true;
		readWorker.quit = true;
		
		try
		{
			this.socket.close();
		} 
		catch (IOException e)
		{
			System.out.println("Client closed socket");
		}
	}
	
	public void writeMessage(String message, User destination) throws IOException
	{
		UserMessage userMessage = new UserMessage(this.user, destination, message);
		out.writeObject(userMessage);		
	}
	
	//this is a call back for the workers
	synchronized public void processMessage (MessageBase mb)
	{
		switch (mb.getType())
		{
		case CONNECT_REQUEST:
			break;
		case CONNECT_RESPONSE:
			break;
		case KEEP_ALIVE:
			break;
		case MULTICAST_ANOUNCMENT:
			break;
		case USER_MESSAGE:
			this.handleUSER_MESSAGE((UserMessage) mb);
			break;
			case NULL:
		default:
			break;
		}
	}
		
	private void handleUSER_MESSAGE (UserMessage message)
	{
		//get the GUI that message needs to be routed too
		ClientUI destination = this.guis.get(message.getDestination().getId());
		//write the message to the GUI
		destination.write(message.getMessage());
	}
}